LLVM/Clangでaws-sdk-cppをビルドする
こんにちは、CX事業本部のうらわです。
aws-sdk-cppのビルドにおいて、Apple Clangではエラーがなかったのですがbrew install llvm
で入手したClang(以降、LLVM/Clangと表記します)では同じコマンドでもエラーがありビルドに失敗してしまいました。
本記事では失敗した点とビルドに成功した対応策をご紹介します。なお、失敗した点は本記事の執筆時点の内容ですので、今後のaws-sdk-cppのアップデートで改善・解消する可能性があります。
作業環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15 # cmakeはbrewでインストールしておきます $ cmake --version cmake version 3.18.4 $ brew info llvm llvm: stable 11.1.0 (bottled), HEAD [keg-only] Next-gen compiler infrastructure https://llvm.org/ /usr/local/Cellar/llvm/11.0.0 (7,910 files, 1.2GB)
aws-sdk-cppのビルドコマンド
以下のコマンドでaws-sdk-cppをクローンしてcmakeでDynamoDBのSDKのコードのみをビルドします。全てビルドするとかなり時間がかかります。
CMAKE_INSTALL_PREFIX
を指定して任意のディレクトリにSDKをインストールします。
git clone https://github.com/aws/aws-sdk-cpp.git cd aws-sdk-cpp mkdir build cd build cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir make make install
LLVM/Clangを使用する設定
MacではCommand Line Tools for XcodeをインストールするとC/C++のデフォルトのコンパイラにApple Clangが設定されます。
$ clang++ --version Apple clang version 12.0.0 (clang-1200.0.32.29) Target: x86_64-apple-darwin19.6.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin
brew install llvm
で入手したLLVM/Clangを使用するにはパスを通す必要があります。
$ export PATH="/usr/local/opt/llvm/bin:$PATH" $ clang++ --version clang version 11.0.0 Target: x86_64-apple-darwin19.6.0 Thread model: posix InstalledDir: /usr/local/opt/llvm/bin
ただし、パスを通しただけではaws-sdk-cppのビルド時は依然としてApple Clangが使用されます。
$ cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir -- Found Git: /usr/local/bin/git (found version "2.30.2") -- TARGET_ARCH not specified; inferring host OS to be platform compilation target -- Building AWS libraries as shared objects -- Building project version: 1.8.160 -- The C compiler identification is AppleClang 12.0.0.12000032 -- The CXX compiler identification is AppleClang 12.0.0.12000032 ...
LLVM/Clangを使うためには環境変数CC
とCXX
を以下のように設定しておきます。
$ export CC="clang" $ export CXX="clang++" $ cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=~/install -- Found Git: /usr/local/bin/git (found version "2.30.2") -- TARGET_ARCH not specified; inferring host OS to be platform compilation target -- Building AWS libraries as shared objects -- Building project version: 1.8.160 -- The C compiler identification is Clang 11.0.0 -- The CXX compiler identification is Clang 11.0.0 ...
これでApple ClangではなくLLVM/Clangでビルドする準備ができました。
aws-c-commonビルド時のエラー
cmakeコマンド実行時に以下のエラーでビルドに失敗しました。
/path/to/aws-sdk-cpp/build/.deps/build/src/AwsCCommon/source/posix/system_info.c:136:34: error: this old-style function definition is not preceded by a prototype [-Werror,-Wstrict-prototypes] const char *s_get_executable_path() { ^ 1 error generated. make[5]: *** [CMakeFiles/aws-c-common.dir/source/posix/system_info.c.o] Error 1 make[4]: *** [CMakeFiles/aws-c-common.dir/all] Error 2 make[3]: *** [all] Error 2 make[2]: *** [build/src/AwsCCommon-stamp/AwsCCommon-build] Error 2 make[1]: *** [CMakeFiles/AwsCCommon.dir/all] Error 2 make: *** [all] Error 2 CMake Error at CMakeLists.txt:224 (message): Failed to build third-party libraries. -- Configuring incomplete, errors occurred!
これはaws-c-commonリポジトリにissueがありました。issueを参考にダウンロードされたコードを直接修正することで解消しました。
- const char *s_get_executable_path() { + static const char *s_get_executable_path() { static const char *s_exe = NULL; if (AWS_LIKELY(s_exe)) { return s_exe; } uint32_t len = sizeof(s_exe_path); if (!_NSGetExecutablePath(s_exe_path, &len)) { s_exe = s_exe_path; } return s_exe; }
make時のエラー
makeコマンド実行時、コンパイラオプションに-Werror
が設定されているため警告がエラーとなりビルドに失敗しました。
[ 41%] Building CXX object testing-resources/CMakeFiles/testing-resources.dir/source/MemoryTesting.cpp.o In file included from /path/to/aws-sdk-cpp/testing-resources/source/MemoryTesting.cpp:9: /path/to/aws-sdk-cpp/testing-resources/include/aws/external/gtest.h:11886:8: error: definition of implicit copy constructor for 'ValueArray2<bool, bool>' is deprecated because it has a user-declared copy assignment operator [-Werror,-Wdeprecated-copy] void operator=(const ValueArray2& other); ^ /path/to/aws-sdk-cpp/testing-resources/include/aws/external/gtest.h:17082:10: note: in implicit copy constructor for 'testing::internal::ValueArray2<bool, bool>' first required here return internal::ValueArray2<T1, T2>(v1, v2); ^ /path/to/aws-sdk-cpp/testing-resources/include/aws/external/gtest.h:17949:10: note: in instantiation of function template specialization 'testing::Values<bool, bool>' requested here return Values(false, true); ^ 1 error generated. make[2]: *** [testing-resources/CMakeFiles/testing-resources.dir/source/MemoryTesting.cpp.o] Error 1 make[1]: *** [testing-resources/CMakeFiles/testing-resources.dir/all] Error 2 make: *** [all] Error 2
これは、コンパイラオプションを変更して回避します。aws-sdk-cpp/cmake/compiler_setting.cmake
のコンパイラオプションを設定している箇所で-Werror
をはずします。
macro(set_gcc_warnings) - list(APPEND AWS_COMPILER_WARNINGS "-Wall" "-Werror" "-pedantic" "-Wextra") + list(APPEND AWS_COMPILER_WARNINGS "-Wall" "-pedantic" "-Wextra") if(COMPILER_CLANG) if(PLATFORM_ANDROID) # when using clang with libc and API lower than 21 we need to include Android support headers and ignore the gnu-include-next warning. if(ANDROID_STL MATCHES "libc" AND ANDROID_NATIVE_API_LEVEL_NUM LESS "21") # NDK lower than 12 doesn't support ignoring the gnu-include-next warning so we need to disable pedantic mode. if(NDK_RELEASE_NUMBER LESS "12000") string(REGEX REPLACE "-pedantic" "" AWS_COMPILER_WARNINGS "${AWS_COMPILER_WARNINGS}") else() list(APPEND AWS_COMPILER_WARNINGS "-Wno-gnu-include-next") endif() endif() endif() endif() endmacro()
または、cmakeコマンド実行時にENABLE_TESTING=OFF
を設定するとテストコードは無視されるため上記のようなエラーは発生しません。
$ cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir -DENABLE_TESTING=OFF $ make
最善策がわからずこれで良いのか…という気がしています。コンパイラオプションの細かな調整はまだまだ勉強不足です。
DynamoDBを試す
無事ビルド・インストールが完了したら、あとは利用するだけです。今回はawslabs/aws-lambda-cppのコード例を参考に、DynamoDBテーブルの作成を試してみます。
create_table.cpp
とCMakeLists.txt
を作成します。
mkdir dynamodb_test cd dynamodb_test touch create_table.cpp touch CMakeLists.txt
#include <aws/core/Aws.h> #include <aws/core/utils/Outcome.h> #include <aws/dynamodb/DynamoDBClient.h> #include <aws/dynamodb/model/AttributeDefinition.h> #include <aws/dynamodb/model/CreateTableRequest.h> #include <aws/dynamodb/model/KeySchemaElement.h> #include <aws/dynamodb/model/ProvisionedThroughput.h> #include <aws/dynamodb/model/ScalarAttributeType.h> #include <iostream> int main() { Aws::SDKOptions options; Aws::InitAPI(options); { const Aws::String table("SampleTable"); const Aws::String region("ap-northeast-1"); Aws::Client::ClientConfiguration clientConfig; if (!region.empty()) clientConfig.region = region; Aws::DynamoDB::DynamoDBClient dynamoClient(clientConfig); Aws::DynamoDB::Model::CreateTableRequest req; Aws::DynamoDB::Model::AttributeDefinition haskKey; haskKey.SetAttributeName("Name"); haskKey.SetAttributeType(Aws::DynamoDB::Model::ScalarAttributeType::S); req.AddAttributeDefinitions(haskKey); Aws::DynamoDB::Model::KeySchemaElement keyscelt; keyscelt.WithAttributeName("Name").WithKeyType(Aws::DynamoDB::Model::KeyType::HASH); req.AddKeySchema(keyscelt); Aws::DynamoDB::Model::ProvisionedThroughput thruput; thruput.WithReadCapacityUnits(5).WithWriteCapacityUnits(5); req.SetProvisionedThroughput(thruput); req.SetTableName(table); const Aws::DynamoDB::Model::CreateTableOutcome& result = dynamoClient.CreateTable(req); if (result.IsSuccess()) { std::cout << "Table " << result.GetResult().GetTableDescription().GetTableName() << " created!" << std::endl; } else { std::cout << "Failed to create table: " << result.GetError().GetMessage(); } } Aws::ShutdownAPI(options); return 0; }
cmake_minimum_required(VERSION 3.8) project(dynamodb-examples) option(BUILD_SHARED_LIBS "Build shared libraries" ON) find_package(AWSSDK REQUIRED COMPONENTS dynamodb) add_executable(create_table create_table.cpp) target_link_libraries(create_table ${AWSSDK_LINK_LIBRARIES})
ビルドします。CMAKE_INSTALL_PREFIX
でさきほどビルドしたaws-sdk-cppのインストールディレクトリを指定します。
mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/path/to/sdk-install-dir make
実行してみます。事前にassume-roleしているため環境変数にクレデンシャルが設定されています。
$ ./create_table Table SampleTable created! * Closing connection 0
おわりに
Apple Clangでは一切エラーが出なかったのですがLLVM/Clangを使用するように変更したら色々つまずいてビルドするのに苦戦しました。
本記事の対応策は正攻法ではないかもしれませんが、LLVM/Clangを利用してaws-sdk-cppをビルドしたい場合の参考になれば幸いです。